/*
 * Copyright 2009 Armando Blancas
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package tests.taskgraph.tasks.data;

import java.io.IOException;

import junit.framework.Assert;
import junit.framework.JUnit4TestAdapter;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import taskgraph.channels.Channel;
import taskgraph.ports.InputPort;
import taskgraph.ports.OutputPort;
import taskgraph.tasks.data.Sum;

public class SumTest {

	/**
	 * Runs the test suite in this class from the command line.
	 * 
	 * @param args	Arguments are ignored.
	 */
	public static void main(String[] args) {
		org.junit.runner.JUnitCore.runClasses(SumTest.class);
	}
	
	/**
	 * Provides compatibility with 3.x versions of JUnit.
	 * 
	 * @return A 3.x-compatible test suite.
	 */
	public static junit.framework.Test suite() {
		return new JUnit4TestAdapter(SumTest.class);
	}
	
	private InputPort<Object> input;
	private OutputPort<Object> output;
	
	@Before
	public void setup() {
		Channel<Object> channel = new Channel<Object>();
		output = channel.getOutputPort();
		input = channel.getInputPort();
	}
	
	@After
	public void cleanup() throws IOException {
		output.close();
		input.close();
	}
	
    /*+----------------------------------------------------------------------+
	  |                                                                      | 
	  | Test the constructors.                                               | 
	  |                                                                      | 
	  +----------------------------------------------------------------------+*/
	
	@Test
	public void defaultConstructor() {
		Sum task = new Sum();
		Assert.assertNotNull(task);
	}
	
	@Test
	public void defaultInstanceClass() {
		Sum task = new Sum();
		Assert.assertEquals(Sum.class, task.getClass());
	}

	@Test
	public void constructorWithPorts() {
		Sum task = new Sum(input, output);
		Assert.assertNotNull(task);
	}
	
	@Test
	public void constructorWithPortsAndClass() {
		Sum task = new Sum(input, output);
		Assert.assertEquals(Sum.class, task.getClass());
	}

    /*+----------------------------------------------------------------------+
	  |                                                                      | 
	  | Test the run method.                                                 | 
	  |                                                                      | 
	  +----------------------------------------------------------------------+*/
	
	@Test
	public void testRunWithBytes() throws IOException {
		Byte[] data = {
			Byte.valueOf((byte)  4),
			Byte.valueOf((byte)  8),
			Byte.valueOf((byte) 16),
			Byte.valueOf((byte) 32),
			Byte.valueOf((byte) 64)
		};
		
		Channel<Object> ch1 = new Channel<Object>();
		Channel<Object> ch2 = new Channel<Object>();
		Sum task = new Sum(ch1.getInputPort(), ch2.getOutputPort());
		
		OutputPort<Object> outputPort = ch1.getOutputPort();
		for (Byte b : data)
			outputPort.write(b);
		outputPort.close();
		
		task.run();
		
		InputPort<Object> inputPort = ch2.getInputPort();
		byte result = (Byte) inputPort.read();
		byte expected = (byte) (4 + 8 + 16 + 32 + 64);
		Assert.assertEquals(expected, result);
		inputPort.close();
	}

	@Test
	public void testRunWithShorts() throws IOException {
		Short[] data = {
			Short.valueOf((short)  24),
			Short.valueOf((short)  48),
			Short.valueOf((short)  96),
			Short.valueOf((short) 192),
			Short.valueOf((short) 384)
		};
		
		Channel<Object> ch1 = new Channel<Object>();
		Channel<Object> ch2 = new Channel<Object>();
		Sum task = new Sum(ch1.getInputPort(), ch2.getOutputPort());
		
		OutputPort<Object> outputPort = ch1.getOutputPort();
		for (Short b : data)
			outputPort.write(b);
		outputPort.close();
		
		task.run();
		
		InputPort<Object> inputPort = ch2.getInputPort();
		short result = (Short) inputPort.read();
		short expected = (short) (24 + 48 + 96 + 192 + 384);
		Assert.assertEquals(expected, result);
		inputPort.close();
	}

	@Test
	public void testRunWithIntegers() throws IOException {
		Integer[] data = {
			Integer.valueOf(1024),
			Integer.valueOf(2048),
			Integer.valueOf(4096),
			Integer.valueOf(8192),
			Integer.valueOf(16384)
		};
		
		Channel<Object> ch1 = new Channel<Object>();
		Channel<Object> ch2 = new Channel<Object>();
		Sum task = new Sum(ch1.getInputPort(), ch2.getOutputPort());
		
		OutputPort<Object> outputPort = ch1.getOutputPort();
		for (Integer b : data)
			outputPort.write(b);
		outputPort.close();
		
		task.run();
		
		InputPort<Object> inputPort = ch2.getInputPort();
		int result = (Integer) inputPort.read();
		int expected = 1024 + 2048 + 4096 + 8192 + 16384;
		Assert.assertEquals(expected, result);
		inputPort.close();
	}

	@Test
	public void testRunWithLongs() throws IOException {
		Long[] data = {
			Long.valueOf(1001024L),
			Long.valueOf(1002048L),
			Long.valueOf(1004096L),
			Long.valueOf(1008192L),
			Long.valueOf(10016384L)
		};
		
		Channel<Object> ch1 = new Channel<Object>();
		Channel<Object> ch2 = new Channel<Object>();
		Sum task = new Sum(ch1.getInputPort(), ch2.getOutputPort());
		
		OutputPort<Object> outputPort = ch1.getOutputPort();
		for (Long b : data)
			outputPort.write(b);
		outputPort.close();
		
		task.run();
		
		InputPort<Object> inputPort = ch2.getInputPort();
		long result = (Long) inputPort.read();
		long expected = 1001024L + 1002048L + 1004096L + 1008192L + 10016384L;
		Assert.assertEquals(expected, result);
		inputPort.close();
	}

	@Test
	public void testRunWithFloats() throws IOException {
		Float[] data = {
			Float.valueOf(1001.024F),
			Float.valueOf(1002.048F),
			Float.valueOf(1004.096F),
			Float.valueOf(1008.192F),
			Float.valueOf(1001.6384F)
		};
		
		Channel<Object> ch1 = new Channel<Object>();
		Channel<Object> ch2 = new Channel<Object>();
		Sum task = new Sum(ch1.getInputPort(), ch2.getOutputPort());
		
		OutputPort<Object> outputPort = ch1.getOutputPort();
		for (Float b : data)
			outputPort.write(b);
		outputPort.close();
		
		task.run();
		
		InputPort<Object> inputPort = ch2.getInputPort();
		float result = (Float) inputPort.read();
		float expected = 1001.024F + 1002.048F + 1004.096F + 1008.192F + 1001.6384F;
		Assert.assertEquals(expected, result);
		inputPort.close();
	}

	@Test
	public void testRunWithDoubles() throws IOException {
		Double[] data = {
			Double.valueOf(1001.024),
			Double.valueOf(1002.048),
			Double.valueOf(1004.096),
			Double.valueOf(1008.192),
			Double.valueOf(1001.6384)
		};
		
		Channel<Object> ch1 = new Channel<Object>();
		Channel<Object> ch2 = new Channel<Object>();
		Sum task = new Sum(ch1.getInputPort(), ch2.getOutputPort());
		
		OutputPort<Object> outputPort = ch1.getOutputPort();
		for (Double b : data)
			outputPort.write(b);
		outputPort.close();
		
		task.run();
		
		InputPort<Object> inputPort = ch2.getInputPort();
		double result = (Double) inputPort.read();
		double expected = 1001.024 + 1002.048 + 1004.096 + 1008.192 + 1001.6384;
		Assert.assertEquals(expected, result);
		inputPort.close();
	}

    /*+----------------------------------------------------------------------+
	  |                                                                      | 
	  | Negative tests for constructors.                                     | 
	  |                                                                      | 
	  +----------------------------------------------------------------------+*/

	@Test(expected=IllegalArgumentException.class)
	public void constructorWithNullInputPort() throws IOException {
		new Sum(null, output);
	}

	@Test(expected=IllegalArgumentException.class)
	public void constructorWithNullOutputPort() throws IOException {
		new Sum(input, null);
	}

    /*+----------------------------------------------------------------------+
	  |                                                                      | 
	  | Negative tests.                                                      | 
	  |                                                                      | 
	  +----------------------------------------------------------------------+*/

}
